from ctypes import Structure, c_uint, c_long, c_int, c_bool, sizeof
import win32clipboard


class ClipboardFileManager:
    """剪切板文件管理工具类，用于操作剪切板中的文件列表（支持复制文件到剪切板）"""

    class _DROPFILES(Structure):
        """内部使用的文件拖放结构体（Windows API 要求的格式）"""
        _fields_ = [
            ("pFiles", c_uint),  # 文件列表在内存中的偏移量
            ("x", c_long),       # 鼠标X坐标（通常为0）
            ("y", c_long),       # 鼠标Y坐标（通常为0）
            ("fNC", c_int),      # 坐标是否相对客户端区域（通常为0）
            ("fWide", c_bool),   # 是否使用Unicode编码（True表示使用）
        ]

    @staticmethod
    def set_files(file_path_list: list) -> None:
        """将文件列表设置到剪切板，支持在资源管理器中粘贴
        
        Args:
            file_path_list (list): 包含文件绝对路径的列表（如 ["C:/test.txt", "D:/data.csv"]）
        
        Raises:
            Exception: 剪切板操作失败时抛出（如无法打开剪切板、权限不足等）
        """
        if not isinstance(file_path_list, list):
            raise TypeError("file_path_list 必须是列表类型")
        if not file_path_list:
            raise ValueError("file_path_list 不能为空列表")

        # 初始化文件拖放结构体
        drop_files = ClipboardFileManager._DROPFILES()
        drop_files.pFiles = sizeof(ClipboardFileManager._DROPFILES())  # 偏移量设为结构体大小
        drop_files.fWide = True  # 使用Unicode编码（支持中文路径）

        # 处理文件路径：转换为Windows格式并拼接为Unicode字符串
        file_paths_str = ""
        for path in file_path_list:
            # 将路径中的正斜杠转为反斜杠（Windows规范）
            win_path = path.replace("/", "\\")
            file_paths_str += win_path + "\0"  # 每个路径以空字符分隔
        file_paths_str += "\0"  # 最终以两个空字符结束（最后一个空字符由上面的循环外补充）

        # 编码为UTF-16（去除BOM头，符合Windows API要求）
        encoded_data = file_paths_str.encode("UTF-16")[2:]

        # 操作剪切板
        win32clipboard.OpenClipboard()
        try:
            win32clipboard.EmptyClipboard()  # 清空现有内容
            # 拼接结构体和文件数据，设置到剪切板
            clipboard_data = bytes(drop_files) + encoded_data
            win32clipboard.SetClipboardData(win32clipboard.CF_HDROP, clipboard_data)
        finally:
            win32clipboard.CloseClipboard()  # 确保剪切板始终被关闭